/*
-----------------------------------------------------------------------------
This file is part of NxGraphics, Multimedia Engine.
Author : Stephane Kyles. Developed in Prague, Czech Republic.
		_   __       ______                     __     _            
	   / | / /_  __ / ____/_____ ____ _ ____   / /_   (_)_____ _____
	  /  |/ /| |/_// / __ / ___// __ `// __ \ / __ \ / // ___// ___/
	 / /|  /_>  < / /_/ // /   / /_/ // /_/ // / / // // /__ (__  ) 
	/_/ |_//_/|_| \____//_/    \__,_// .___//_/ /_//_/ \___//____/  
									/_/                             
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#ifndef __NXGRAPHICSMATERIALMANAGER_H__
#define __NXGRAPHICSMATERIALMANAGER_H__

#include "NxGraphics_Prerequisites.h"

namespace NxGraphics_Namespace {

enum NxSceneBlendType
{
	/// Make the object transparent based on the final alpha values in the texture
	NXBLEND_TRANSPARENT_ALPHA,
	/// Make the object transparent based on the colour values in the texture (brighter = more opaque)
	NXBLEND_TRANSPARENT_COLOUR,
	/// Add the texture values to the existing scene content
	NXBLEND_ADD,
	/// Multiply the 2 colours together
	NXBLEND_MODULATE,
	/// The default blend mode where source replaces destination
	NXBLEND_REPLACE
	// TODO : more
};

enum NxTextureAddressingMode
{
	/// Texture wraps at values over 1.0
	TEXTURE_WRAP,
	/// Texture mirrors (flips) at joins over 1.0
	TEXTURE_MIRROR,
	/// Texture clamps at 1.0
	TEXTURE_CLAMP,
	/// Texture coordinates outside the range [0.0, 1.0] are set to the border colour
	TEXTURE_BORDER
};

class NxGraphics_Export NxTextureUnit
{
public :
	//! NxTextureUnit Class Constructor.
	NxTextureUnit( NxPass * parent, const std::string & TextureUnitName );
	//! NxTextureUnit Class Deconstructor.
	~NxTextureUnit();
	//! Get Material Name.
	const std::string & GetName() const;
	//! Set Colour Operation.
	void SetColourOperation( const Ogre::LayerBlendOperation op );
	//! Set Texture Scale.
	void SetTextureScale( float ScaleX, float ScaleY );
	//! Set Texture Rotation.
	void SetTextureRotate( float degree );
	//! Set Texture File Name.
	void SetTexture( const std::string & TextureFile );
	//! Get Texture Unit.
	Ogre::TextureUnitState * GetTextureUnit();
	//! Set Alpha Operation.
	void SetAlphaOperation( Ogre::LayerBlendOperationEx op, 
		Ogre::LayerBlendSource source1 = Ogre::LBS_TEXTURE,
		Ogre::LayerBlendSource source2 = Ogre::LBS_CURRENT,
		float arg1 = 1.0, float arg2 = 1.0, float manualBlend = 0.0 );

	void SetTextureAnisotropy( unsigned int MaxAnisotropy );
	void SetTextureBorderColour( const Ogre::ColourValue& BorderColour );
	void SetTextureAddressingMode( NxTextureAddressingMode tam );
	unsigned int GetTextureWidth();
	unsigned int GetTextureHeight();
private :
	Ogre::TextureUnitState * mTextureUnit;
};



class NxGraphics_Export NxPass
{
private :
    typedef vector<NxTextureUnit*>::type Units;
    /// List of primary units
    Units mUnits;
public :
	//! NxPass Class Constructor.
	NxPass( NxTechnique * parent, const std::string & PassName );
	//! NxPass Class Deconstructor.
	~NxPass();
	//! Create a Texture Unit.
	NxTextureUnit * CreateTextureUnit( const std::string & FileName );
	//! Get Texture Unit.
	NxTextureUnit * GetTextureUnit( const std::string & name );
	//! Get technique Name.
	const std::string & GetName() const;
	//! Get number of Texture Units.
	unsigned short GetNumTextureUnit() const;
	//! Set Diffuse.
	void SetDiffuse( const Ogre::ColourValue& diffuse );
	//! Set Ambient.
	void SetAmbient( const Ogre::ColourValue& ambient );
	//! Set Specular.
	void SetSpecular(const Ogre::ColourValue& specular);
	//! Set Scene Blending
	void SetSceneBlending( const NxSceneBlendType sbt );
	//! Get Pass
	Ogre::Pass * GetPass();
private :
	Ogre::Pass * mPass;
};

class NxGraphics_Export NxTechnique
{
private :
    typedef vector<NxPass*>::type Passes;
    /// List of primary passes
    Passes mPasses;
public :
	//! NxTechnique Class Constructor.
	NxTechnique( MaterialNx * Material, const std::string & TechniqueName );
	//! NxTechnique Class Destructor.
	~NxTechnique();
	//! Get technique Name
	const std::string & GetName() const;
	//! create a pass
	NxPass * CreatePass();
	//! Create a Pass
	NxPass * CreatePass( const std::string & PassName );
	//! Get Technique by Index.
	NxPass * GetPass( unsigned short index );
	//! Get Technique by Name.
	NxPass * GetPass( const std::string & name );
	//! Get total number of techniques.
	unsigned short GetNumPasses() const;
	//! Get technique.
	Ogre::Technique * GetTechnique();
private :
	Ogre::Technique * mTechnique;
};


//!  A class to manage a materials
/*!
	Technique Creation, management.
*/
class NxGraphics_Export MaterialNx
{
private :
    typedef vector<NxTechnique*>::type Techniques;
	//! All techniques supported.
    Techniques mTechniques;
public :
	//! MaterialNx Class Constructor.
	MaterialNx( const std::string & MaterialName );
	//! MaterialNx Class Destructor.
	~MaterialNx();
	//! Get Material Name.
	const std::string & GetName() const;
	//! Set Ambient.
	void SetAmbient( const Ogre::ColourValue & ambient );
	//! Set Diffuse.
	void SetDiffuse( const Ogre::ColourValue & diffuse );
	//! Set Specular.
	void SetSpecular( const Ogre::ColourValue & specular );
	//! material affected by light ?
	void SetLightingEnabled( bool Enabled );
	//! Set material self illumination colour.
	void SetSelfIllumination( float red, float green, float blue );
	//! Set material receive shadows.
	void SetReceiveShadows( bool ReceiveShadows );
	//! create a technique
	NxTechnique * CreateTechnique();
	//! Create a Technique with a specified name.
	NxTechnique * CreateTechnique( const std::string & TechniqueName );
	//! Get Technique by Index.
	NxTechnique * GetTechnique( unsigned short index );
	//! Get Technique by Name.
	NxTechnique * GetTechnique( const std::string & name );
	//! Get total number of techniques.
	unsigned short GetNumTechniques() const;
	//! Get Ogre Material
	Ogre::MaterialPtr GetMaterial();
private :
	Ogre::MaterialPtr mMaterial;
};

//!  A class to manage a materials
/*!
	Material Creation, management.
*/
class NxGraphics_Export NxMaterialManager : public Singleton<NxMaterialManager>
{
private :
    typedef vector<MaterialNx*>::type Materials;
	//! All techniques supported.
    Materials mMaterials;
public :
	//! NxMaterialManager Class Constructor.
	NxMaterialManager();
	//! NxMaterialManager Class Destructor.
	~NxMaterialManager();
	//! NxMaterialManager Singleton.
	static NxMaterialManager& getSingleton();
	//! NxMaterialManager Singleton.
	static NxMaterialManager* getSingletonPtr();
	//! Create a Material
	MaterialNx * CreateMaterial( const std::string & MaterialName );
	//! get material by name
	MaterialNx * GetMaterial( const std::string & MaterialName );
	//! Create a cubeMap Material.
	void CreateCubemapMaterial( const std::string & MaterialName, Ogre::Entity * Ent );
};

template<> NxMaterialManager* Singleton<NxMaterialManager>::ms_Singleton = 0;


}//namespace

#endif